/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package espe.ccsoft.controllers;

import espe.ccsoft.controllers.utils.PaginationHelper;
import espe.ccsoft.dao.FeriadoDao;
import espe.ccsoft.dao.RolDao;
import espe.ccsoft.dao.RotacionDao;
import espe.ccsoft.dao.RutaDao;
import espe.ccsoft.models.Feriados;
import espe.ccsoft.models.Rotacion;
import espe.ccsoft.models.Ruta;
import espe.ccsoft.viewmodels.ResumenRotacion;
import java.math.BigDecimal;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;

/**
 *
 * @author Carlos
 */
@ManagedBean
@RequestScoped
public class RotacionController {

    private static Date fechaInicio = new Date();
    private static List<Rotacion> rotacionesOrd = new ArrayList<>();
    private static List<Rotacion> rotacionesSab = new ArrayList<>();
    private static List<Rotacion> rotacionesDom = new ArrayList<>();
    private static List<String> rutas = new ArrayList<>();
    private static List<ResumenRotacion> resumenRotacion = new ArrayList<>();
    private static int unidadInicial = 0;
    private static int unidadFinal = 0;
    private static int unidadInicialDescanso = 0;    

    private Rotacion rotacion;
    private RotacionDao rotacionDao = new RotacionDao();
    private FeriadoDao feriadoDao = new FeriadoDao();
    private RutaDao rutaDao = new RutaDao();
    private PaginationHelper pagination;
    private int selectedItemIndex;

    private static List<Date> fechaOrdinarios = new ArrayList<>();
    private static List<Date> fechaSabados = new ArrayList<>();
    private static List<Date> fechaDomingos = new ArrayList<>();
    private static List<List<Integer>> diasOrd = new ArrayList<>();
    private static List<List<Integer>> diasSab = new ArrayList<>();
    private static List<List<Integer>> diasDom = new ArrayList<>();
    private static List<String> rutaOrd = new ArrayList<>();
    private static List<String> rutaSab = new ArrayList<>();
    private static List<String> rutaDom = new ArrayList<>();

    public Rotacion getSelected() {
        if (rotacion == null) {
            rotacion = new Rotacion();
            selectedItemIndex = -1;
        }
        return rotacion;
    }

    public RotacionDao getRolDao() {
        rotacionDao = new RotacionDao();
        return rotacionDao;
    }

    public RutaDao getRutaDao() {
        rutaDao = new RutaDao();
        return rutaDao;
    }

    public Date getFechaInicio() {
        return fechaInicio;
    }

    public void setFechaInicio(Date fechaInicio) {
        this.fechaInicio = fechaInicio;
    }

    public List<String> getRutas() {
        return rutas;
    }

    public void setRutas(List<String> rutas) {
        this.rutas = rutas;
    }

    public int getUnidadInicial() {
        return unidadInicial;
    }

    public void setUnidadInicial(int unidadInicial) {
        this.unidadInicial = unidadInicial;
    }

    public int getUnidadFinal() {
        return unidadFinal;
    }

    public void setUnidadFinal(int unidadFinal) {
        this.unidadFinal = unidadFinal;
    }

    public int getUnidadInicialDescanso() {
        return unidadInicialDescanso;
    }

    public void setUnidadInicialDescanso(int unidadInicialDescanso) {
        this.unidadInicialDescanso = unidadInicialDescanso;
    }

    public List<Date> getFechaOrdinarios() {
        return fechaOrdinarios;
    }

    public void setFechaOrdinarios(List<Date> fechaOrdinarios) {
        this.fechaOrdinarios = fechaOrdinarios;
    }

    public List<Rotacion> getRotacionesOrd() {
        return rotacionesOrd;
    }

    public void setRotacionesOrd(List<Rotacion> rotacionesOrd) {
        this.rotacionesOrd = rotacionesOrd;
    }

    public List<Rotacion> getRotacionesSab() {
        return rotacionesSab;
    }

    public void setRotacionesSab(List<Rotacion> rotacionesSab) {
        this.rotacionesSab = rotacionesSab;
    }

    public List<Rotacion> getRotacionesDom() {
        return rotacionesDom;
    }

    public void setRotacionesDom(List<Rotacion> rotacionesDom) {
        this.rotacionesDom = rotacionesDom;
    }

    public List<ResumenRotacion> getResumenRotacion() {
        return resumenRotacion;
    }

    public void setResumenRotacion(List<ResumenRotacion> resumenRotacion) {
        this.resumenRotacion = resumenRotacion;
    }

    public List<List<Integer>> getDiasOrd() {
        return diasOrd;
    }

    public void setDiasOrd(List<List<Integer>> dias) {
        this.diasOrd = dias;
    }

    public List<List<Integer>> getDiasSab() {
        return diasSab;
    }

    public void setDiasSab(List<List<Integer>> diasSab) {
        this.diasSab = diasSab;
    }

    public List<List<Integer>> getDiasDom() {
        return diasDom;
    }

    public void setDiasDom(List<List<Integer>> diasDom) {
        this.diasDom = diasDom;
    }

    public List<Date> getFechaSabados() {
        return fechaSabados;
    }

    public void setFechaSabados(List<Date> fechaSabados) {
        this.fechaSabados = fechaSabados;
    }

    public List<Date> getFechaDomingos() {
        return fechaDomingos;
    }

    public void setFechaDomingos(List<Date> fechaDomingos) {
        this.fechaDomingos = fechaDomingos;
    }

    public  List<String> getRutaOrd() {
        return rutaOrd;
    }

    public  void setRutaOrd(List<String> rutaOrd) {
        this.rutaOrd = rutaOrd;
    }

    public  List<String> getRutaSab() {
        return rutaSab;
    }

    public  void setRutaSab(List<String> rutaSab) {
        this.rutaSab = rutaSab;
    }

    public  List<String> getRutaDom() {
        return rutaDom;
    }

    public void setRutaDom(List<String> rutaDom) {
        this.rutaDom = rutaDom;
    }
    
    

    // <editor-fold defaultstate="collapsed" desc="Métodos">                          
    public void crearRotacion() throws Exception {
            
        int numOrdinario = contarUnidades(rutas, "ORDINARIO");
        int numSabados = contarUnidades(rutas, "SÁBADO");
        int numDomingos = contarUnidades(rutas, "DOMINGO");
        
        List<Integer> identificadoresOrd = encotrarIdentificadores(rutas,"ORDINARIO");
        List<Integer> identificadoresSab = encotrarIdentificadores(rutas,"SÁBADO");
        List<Integer> identificadoresDom = encotrarIdentificadores(rutas,"DOMINGO");
        
        int numDia;
        int count = 0;
        int id = 1;
        int idFecha = 1;
        
        Date fechaInicialTmp = fechaInicio;
        int auxInicialOrd = unidadInicial;        
        int auxInicialDes = unidadInicialDescanso;        

            
        while (count < numOrdinario) {
            numDia = dayOfTheWeek(fechaInicialTmp);

            if (numDia == 1) { //Domingo         
                for (int i = 0; i < numDomingos; i++) {
                    Rotacion rotacionTmp = new Rotacion();
                    rotacionTmp.setId(id);
                    rotacionTmp.setFecha(fechaInicialTmp);
                    rotacionTmp.setTipoDia("DOMINGO");
                    rotacionTmp.setUnidad(auxInicialDes);
                    rotacionTmp.setOrden(i + 1);
                    rotacionTmp.setIdFecha(idFecha);
                    rotacionTmp.setIdRuta(identificadoresDom.get(i));
                    rotacionesDom.add(rotacionTmp);                    
                    auxInicialDes++;
                    if (auxInicialDes > unidadFinal) {
                        auxInicialDes = unidadInicial;
                    }
                }
            } else if (numDia == 7 || fechaFeriado(fechaInicialTmp)==true) { //Sabado    
                for (int i = 0; i < numSabados; i++) {
                    Rotacion rotacionTmp = new Rotacion();
                    rotacionTmp.setId(id);
                    rotacionTmp.setFecha(fechaInicialTmp);
                    rotacionTmp.setTipoDia("SÁBADO");
                    rotacionTmp.setUnidad(auxInicialDes);
                    rotacionTmp.setOrden(i + 1);
                    rotacionTmp.setIdFecha(idFecha);
                    rotacionTmp.setIdRuta(identificadoresSab.get(i));
                    rotacionesSab.add(rotacionTmp);                    
                    auxInicialDes++;
                    if (auxInicialDes > unidadFinal) {
                        auxInicialDes = unidadInicial;
                    }
                }

            } else { //Ordinario                     
                for (int i = 0; i < numOrdinario; i++) {
                    Rotacion rotacionTmp = new Rotacion();
                    rotacionTmp.setId(id);
                    rotacionTmp.setFecha(fechaInicialTmp);
                    rotacionTmp.setTipoDia("ORDINARIO");
                    rotacionTmp.setUnidad(auxInicialOrd);
                    rotacionTmp.setOrden(i + 1);
                    rotacionTmp.setIdFecha(idFecha);
                    rotacionTmp.setIdRuta(identificadoresOrd.get(i));
                    rotacionesOrd.add(rotacionTmp);                    
                    auxInicialOrd++;
                    if (auxInicialOrd > unidadFinal) {
                        auxInicialOrd = unidadInicial;
                    }

                    if (i == 31) {
                        System.out.print("");
                    }

                }
                count = count + 1;
                auxInicialOrd++;
            }
            idFecha++;
            fechaInicialTmp = addDayDate(fechaInicialTmp);
        }
        ObtenerfechasOrdinarios();
        ObtenerfechasSabados();
        ObtenerfechasDomingos();
        CargarResumen();
    }

    public int dayOfTheWeek(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);

        int day = calendar.get(Calendar.DAY_OF_WEEK);
        return day;
    }

    public Date addDayDate(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        return calendar.getTime();
    }

    public int contarUnidades(List<String> rutas, String tipoDia) {
        int count = 0;
        try {
            for (String aux : rutas) {

                Ruta rutaTmp = rutaDao.findByNombreDia(aux, tipoDia);
                count = count + rutaTmp.getNumBuses();

            }
        } catch (Exception ex) {
            Logger.getLogger(RotacionController.class.getName()).log(Level.SEVERE, null, ex);
        }
        return count;
    }

    public void ObtenerfechasOrdinarios() throws Exception {
        fechaOrdinarios = new ArrayList<Date>();
        Date fechaInicial = fechaInicio;
        int i = 0;
        while (i < contarUnidades(rutas, "ORDINARIO")) {
            if (dayOfTheWeek(fechaInicial) > 1 && dayOfTheWeek(fechaInicial) < 7 && fechaFeriado(fechaInicial)!=true) {
                fechaOrdinarios.add(fechaInicial);
                i++;
            }
            fechaInicial = addDayDate(fechaInicial);
        }
        obtenerCuadroOrdinario();
    }

    public void obtenerCuadroOrdinario() throws Exception {
        rutaOrd = new ArrayList<>();
        for (int i = 1; i <= contarUnidades(rutas, "ORDINARIO"); i++) {
            ArrayList<Integer> tmp = new ArrayList<>();
            for (Rotacion aux : rotacionesOrd) {
                if (aux.getOrden() == i) {
                    tmp.add(aux.getUnidad());                    
                }
            }
            diasOrd.add(tmp);                                    
        }
        
        for (String aux: rutas) {
            Ruta ruta = rutaDao.findByNombre(aux);
            
            for(int i=0; i<ruta.getNumBuses();i++)
            {
                rutaOrd.add(ruta.getCodigo());
            }      
            int i=0;
        }
        
    }

    public void ObtenerfechasSabados() throws Exception {
        fechaSabados = new ArrayList<Date>();
        Date fechaInicial = fechaInicio;
        int i = 0;
        while (i < contarUnidades(rutas, "ORDINARIO")) {
            if (dayOfTheWeek(fechaInicial) > 1 && dayOfTheWeek(fechaInicial) < 7 && fechaFeriado(fechaInicial)!=true) {
                i++;
            } else if (dayOfTheWeek(fechaInicial) == 7 || fechaFeriado(fechaInicial)==true ) {
                fechaSabados.add(fechaInicial);
            }
            fechaInicial = addDayDate(fechaInicial);
        }
        obtenerCuadroSabados();
    }

    public void obtenerCuadroSabados() throws Exception {
        rutaSab = new ArrayList<>();
        for (int i = 1; i <= contarUnidades(rutas, "SÁBADO"); i++) {
            ArrayList<Integer> tmp = new ArrayList<>();
            for (Rotacion aux : rotacionesSab) {
                if (aux.getOrden() == i) {
                    tmp.add(aux.getUnidad());
                }
            }
            diasSab.add(tmp);
        }
        for (String aux: rutas) {
            Ruta ruta = rutaDao.findByNombre(aux);
            
            for(int i=0; i<ruta.getNumBuses();i++)
            {
                rutaSab.add(ruta.getCodigo());
            }            
        }
    }

    public void ObtenerfechasDomingos() throws Exception {
        fechaDomingos = new ArrayList<Date>();
        Date fechaInicial = fechaInicio;
        int i = 0;
        while (i < contarUnidades(rutas, "ORDINARIO")) {
            if (dayOfTheWeek(fechaInicial) > 1 && dayOfTheWeek(fechaInicial) < 7) {
                i++;
            } else if (dayOfTheWeek(fechaInicial) == 1) {
                fechaDomingos.add(fechaInicial);
            }
            fechaInicial = addDayDate(fechaInicial);
        }
        obtenerCuadroDomingos();
    }

    public void obtenerCuadroDomingos() throws Exception {
        rutaDom = new ArrayList<>();
        for (int i = 1; i <= contarUnidades(rutas, "DOMINGO"); i++) {
            ArrayList<Integer> tmp = new ArrayList<>();
            for (Rotacion aux : rotacionesDom) {
                if (aux.getOrden() == i) {
                    tmp.add(aux.getUnidad());
                }
            }
            diasDom.add(tmp);
        }
        for (String aux: rutas) {
            Ruta ruta = rutaDao.findByNombre(aux);
            
            for(int i=0; i<ruta.getNumBuses();i++)
            {
                rutaDom.add(ruta.getCodigo());
            }            
        }
    }

    public void CargarResumen() throws Exception {
        for (int i = unidadInicial; i <= unidadFinal; i++) {
            ResumenRotacion resumen = new ResumenRotacion();
            BigDecimal bigDecimal = new BigDecimal(0);
            RutaDao dao = new RutaDao();
            for (Rotacion aux : rotacionesOrd) {
                if (aux.getUnidad() == i) {
                    resumen.setDias(resumen.getDias() + 1);
                    resumen.setUnidad(i);
                    Ruta rutaTmp1 = dao.findByPK(aux.getIdRuta());
                    bigDecimal = bigDecimal.add(BigDecimal.valueOf(rutaTmp1.getDistancia()));

                }
            }

            for (Rotacion aux2 : rotacionesSab) {
                if (aux2.getUnidad() == i) {
                    resumen.setDias(resumen.getDias() + 1);
                    resumen.setUnidad(i);
                    Ruta rutaTmp2 = dao.findByPK(aux2.getIdRuta());
                    bigDecimal = bigDecimal.add(BigDecimal.valueOf(rutaTmp2.getDistancia()));
                }
            }

            for (Rotacion aux3 : rotacionesDom) {
                if (aux3.getUnidad() == i) {
                    resumen.setDias(resumen.getDias() + 1);
                    resumen.setUnidad(i);
                    Ruta rutaTmp3 = dao.findByPK(aux3.getIdRuta());
                    bigDecimal = bigDecimal.add(BigDecimal.valueOf(rutaTmp3.getDistancia()));
                }
            }
            resumen.setKilometraje(bigDecimal);
            resumenRotacion.add(resumen);
        }
    }

    public void guardarRotación() throws Exception {
        rotacionDao.insert(rotacionesOrd);
        rotacionDao.insert(rotacionesSab);
        rotacionDao.insert(rotacionesDom);
    }

    public String cargarCrearRotacion() {
        rotacion = new Rotacion();
        return "crear";

    }
    // </editor-fold> 

    private boolean fechaFeriado(Date fechaInicialTmp) {        
        Feriados feriado =feriadoDao.findFeriado(fechaInicialTmp);
        return feriado!=null;
    }

    private List<Integer> encotrarIdentificadores(List<String> rutas, String tipoDia) {
        ArrayList<Integer> count = new ArrayList<>();
        try {
            for (String aux : rutas) {

                Ruta rutaTmp = rutaDao.findByNombreDia(aux, tipoDia);
                for(int i=0; i<rutaTmp.getNumBuses(); i++)
                {
                    count.add(rutaTmp.getId());
                    
                }                
            }
            return count;
        } catch (Exception ex) {
            Logger.getLogger(RotacionController.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }
}
